# Dada uma lista de arquivos que contem instrucoes e suas micros (formatacao descriminada abaixo)
# gera os seguintes arquivos:
#     instrucoes.txt: contem as instrucoes e suas micros ja em formato para o parser
#     microinstrucoes.txt: contem todas as microinstrucoes possiveis

import sys

def filtra(string):
    ''' Remove espacos em branco, returns e tabs'''

    string = string.replace("\n", "").replace("\t", "")
    string = string.split(" ")

    r = ''
    for c in string:
        if c != '':
            r = r + c + ' '

    return r

def change_value(instrucao, micros, variavel, valores, expressao=None):
    dic = {}

    for i in valores:
        chave = instrucao.replace(variavel, str(i))

        cpy_micros = []
        for micro in micros:

            if expressao == None:
                cpy_micros.append(micro.replace(variavel, str(i)))

            else:
                k = eval(expressao.replace('X', str(i)))
                cpy_micros.append(micro.replace(variavel, str(i)).replace('_K', str(k)))

        dic[chave] = cpy_micros

    return dic


def replace_tokens(dic):
    retorno = {}

    for instrucao in dic.keys():
        micros = dic[instrucao]['micro']
        x = dic[instrucao]['X']
        y = dic[instrucao]['Y']
        k = dic[instrucao]['K']

        if (x != None):
            x_change = change_value(instrucao, micros, '_X', x, k)

            if (y != None):
                y_change = {}

                for i in x_change.keys():
                    micros_i = x_change[i]
                    y_change.update(change_value(i, micros_i, '_Y', y))

                retorno.update(y_change)

            else:
                retorno.update(x_change)
        else:
            retorno.update({instrucao:micros})

    return retorno

    
def add_buscaInstrucao(instrucao, dic):
    buscaInstrucao = ['Rend <- PC ', 'Rdados <- [Rend] ', 'Rinst <- Rdados ']

    if instrucao != None:
        dic[instrucao]['micro'] += buscaInstrucao[:]

def create_dict(files):
    ''' Retorna um dicionario com as insformacoes lidas dos arquivos para cada instrucao'''

    lines = []
    for file_name in files:
        file = open(file_name, 'r')
        lines += file.readlines()
        file.close()

    instrucao = None
    dic = {}

    for line in lines:
        if line[0] == '?':
            add_buscaInstrucao(instrucao, dic)

            instrucao = line[1:-1]
            dic[instrucao] = {'micro':[], 'X':None, 'Y':None, 'K':None}

        elif line[0] == ' ' or line[0] == '\t':
            line = filtra(line)
            if len(line) <= 0:
                continue

            dic[instrucao]['micro'].append(line)

        elif line[:2] == "@X":
            aux = line.split('=')[1].strip()
            dic[instrucao]['X'] = eval(aux)

        elif line[:2] == "@Y":
            aux = line.split('=')[1].strip()
            dic[instrucao]['Y'] = eval(aux)

        elif line[:2] == "@K":
            aux = line.split('=')[1].strip()
            dic[instrucao]['K'] = aux

    add_buscaInstrucao(instrucao, dic)

    return dic


def print_dic(dic, value):
    micro_instrucao = set()

    print "------ INSTRUCOES: %d" % len(dic.keys())
    instrucao = list(dic.keys())
    instrucao.sort()
    for i in instrucao:
        print i
        for mi in dic[i]:
            micro_instrucao.add(mi)
    print "-" * 10
    print "-" * 10
    print "------ MICRO INSTRUCOES: %d" % len(micro_instrucao)
    file = open('pasta_aux/[' + value +']conjuntoMicroinstrucoes.txt', 'w')
    micro_instrucao = list(micro_instrucao)
    micro_instrucao.sort()
    for i in micro_instrucao:
        file.write(i)
        file.write('\n')
        print i
    print "-" * 10
    print "-" * 10
    file.close()

    file = open('pasta_aux/[' + value + ']conjuntoInstrucoes.txt', 'w')
    keys = list(dic.keys())
    keys.sort()
    for instrucao in keys:
        file.write(instrucao)
        file.write('\n')
    file.close()

    file = open('pasta_aux/[' + value + ']instrucoes.txt', 'w')
    keys = list(dic.keys())
    keys.sort()
    for instrucao in keys:
        file.write(instrucao)
        file.write('\n')
        print instrucao
        for microinstrucao in dic[instrucao]:
            file.write(microinstrucao)
            file.write('\n')
            print microinstrucao
        file.write('\n')
        print
    file.close()


def main(value):
    files = ['entrada/[1]MicroADD.txt', 'entrada/[1]MicroSUB.txt', 'entrada/[1]MicroMOV.txt', 'entrada/[1]MicroCMP.txt', 'entrada/[1]MicroAND.txt', 'entrada/[1]MicroOR.txt', 'entrada/[1]MicroNOT.txt', 'entrada/[1]MicroCLR.txt', 'entrada/[1]MicroNEG.txt', 'entrada/[1]MicroSHL.txt', 'entrada/[1]MicroSHR.txt', 'entrada/[1]MicroBR_JMP.txt', 'entrada/[1]MicroSTART.txt', 'entrada/[1]MicroCLF.txt', 'entrada/[1]MicroSTART.txt', 'entrada/[1]MicroINC_DEC.txt', 'entrada/[1]MicroLOOP.txt', 'entrada/[1]MicroNOP.txt', 'entrada/[1]MicroPOP_PUSH.txt', 'entrada/[1]MicroXCHG.txt', 'entrada/[1]MicroJ.txt']
    dic = create_dict(files)
    new_dic = replace_tokens(dic)

    print_dic(new_dic, value)










if __name__ == '__main__':
    value = ""

    if len(sys.argv) > 1:
        value = sys.argv[1]
    
    main(value)
            
